package com.ams.admin.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.ams.admin.mapper.UserMapper;
import com.ams.admin.pojo.entity.User;
import com.ams.admin.service.UserService;
import com.ams.admin.utils.wx.*;
import com.ams.common.base.result.R;
import com.ams.common.base.result.ResultCode;
import com.ams.common.redis.util.RedisUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Like
 * @Date: 2023/5/26 16:18
 * @Description:
 */
@Service
public class UserServiceImpl implements UserService {

    @Value("${wx.appId}")
    private String MP_APP_ID;
    @Value("${wx.appSecret}")
    private String MP_APP_SECRET;
    @Value("${wx.code2Session}")
    private String OPENID_URL;
    @Autowired
    private RedisUtils redisUtils;

    public String getOpenidUrl(String code) {
        String url = "{OPENID_URL}?appid={MP_APP_ID}&secret={MP_APP_SECRET}&js_code={code}&grant_type=authorization_code";
        String newUrl = url.replace("{OPENID_URL}", OPENID_URL)
                .replace("{MP_APP_ID}", MP_APP_ID)
                .replace("{MP_APP_SECRET}", MP_APP_SECRET)
                .replace("{code}", code);
        return newUrl;
    }

    @Autowired
    private WxService wxService;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public R authLogin(WXAuth wxAuth) {
        try {
            String json = wxService.wxDecrypt(wxAuth.getEncryptedData(), wxAuth.getSessionId(), wxAuth.getIv());
            WxUserInfo wxUserInfo = JSON.parseObject(json, WxUserInfo.class);

            String value = redisTemplate.opsForValue().get(RedisKey.WX_SESSION_ID + wxAuth.getSessionId());
            String a = (String) JSON.parse(value);
            JSONObject jsonObject = JSON.parseObject(a);
            wxUserInfo.setOpenId(jsonObject.getString("openid"));
            String openId = wxUserInfo.getOpenId();
            User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getOpenId, openId).last("limit 1"));
            if (user != null) {
                //登录成功
                UserDto userDto = new UserDto();
                BeanUtils.copyProperties(user, userDto);
                return R.ok(this.login(userDto));
            } else {
                UserDto userDto = new UserDto();
                userDto.from(wxUserInfo);
                return this.register(userDto);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return R.failed();
    }

    @Override
    public R toLogin(String sessionId) {
        try {
            String value = redisTemplate.opsForValue().get(RedisKey.WX_SESSION_ID + sessionId);
            String a = (String) JSON.parse(value);
            JSONObject jsonObject = JSON.parseObject(a);
            String openId = jsonObject.getString("openid");
            User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getOpenId, openId).last("limit 1"));
            if (user != null) {
                //登录成功
                UserDto userDto = new UserDto();
                BeanUtils.copyProperties(user, userDto);
                return R.ok(this.login(userDto));
            } else {
                UserDto userDto = new UserDto();
                userDto.setOpenId(openId);
                return this.register(userDto);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return R.failed();
    }

    @Override
    public R updateUser(String token,UserDto userDto, String sessionId) {
        //1.校验token是否有效
        R result = this.userinfo(token, true);
        String code = result.getCode();
        if (!code.equals("000000")){
            return R.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED);
        }
        //2.根据用户id去查询用户是否存在
        User queryUser = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getId, userDto.getId()));
        if (queryUser == null) {
            return R.failed(ResultCode.USER_NOT_EXIST);
        }
        //3.更新用户信息
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        userMapper.updateById(user);
        UserDto oldUser = (UserDto)result.getData();
        userDto.setToken(oldUser.getToken());
        return R.ok(userDto);
    }

    @Override
    public R findUser(String token, UserDto userDto) {
        //1.校验token是否有效
        R result = this.userinfo(token, true);
        String code = result.getCode();
        if (!code.equals("000000")){
            return R.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED);
        }
        UserDto oldUser = (UserDto)result.getData();
        User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getId, userDto.getId()));
        if (user == null) {
            return R.failed(ResultCode.USER_NOT_EXIST);
        }
        BeanUtils.copyProperties(user, oldUser);
        oldUser.from(oldUser);
        return R.ok(oldUser);
    }

    public UserDto login(UserDto userDto) {
        // 登录成功 封装用户信息到token
        userDto.setPassWord(null);
        userDto.setUserName(null);
        userDto.setOpenId(null);
        userDto.setWxUnionId(null);
        String token = JWTUtils.sign(userDto.getId());
        userDto.setToken(token);
        //保存到redis内,下次就直接跳过验证
        redisTemplate.opsForValue().set(RedisKey.TOKEN_KEY + token, JSON.toJSONString(userDto), 7, TimeUnit.DAYS);
        return userDto;
    }

    public R register(UserDto userDto) {
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        User queryUser = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getOpenId, user.getOpenId()));
        if (queryUser == null) {
            userMapper.insert(user);
        }
        //已存在直接登录
        return R.ok(login(userDto));
    }


    @Override
    public R getSessionKeyOropenid(String code) {
        //微信端登录code值
        String res = HttpUtil.get(getOpenidUrl(code));
        JSONObject jsonObject = JSON.parseObject(res);
        if (jsonObject.get("openid") == null) {
            return R.failed(ResultCode.CODE_ERROR);
        }
        String uuid = UUID.randomUUID().toString();
        redisUtils.set(RedisKey.WX_SESSION_ID + uuid, res, 600);
        Map<String, String> map = new HashMap<>();
        map.put("sessionId", uuid);
        return R.ok(map);
    }


    @Override
    public R userinfo(String token, Boolean refresh) {
        /**
         * 1. 根据token 来验证此token 是否有效
         * 2. refresh 如果为true 代表刷新 重新生成token和redis里面重新存储 续期
         * 3. false直接返回用户信息 -》 redis中 查询出来 直接返回
         */
        token = token.replace("Bearer ", "");
        boolean verify = JWTUtils.verify(token);
        if (!verify) {
            return R.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED, "未登录");
        }
        String userJson = redisTemplate.opsForValue().get(RedisKey.TOKEN_KEY + token);
        if (StringUtils.isBlank(userJson)) {
            return R.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED, "未登录");
        }
        UserDto userDto = JSON.parseObject(userJson, UserDto.class);
        if (refresh) {
            token = JWTUtils.sign(userDto.getId());
            userDto.setToken(token);
            redisTemplate.opsForValue().set(RedisKey.TOKEN_KEY + token, JSON.toJSONString(userDto), 7, TimeUnit.DAYS);
        }
        return R.ok(userDto);
    }
}